<?php

class AccessrightDAO {
	// debug-Logger
	static $debug;
	
	// Datenbank Objekt
	private $db;
	
	// Hier steht immer der aktuellste Fehler drin
	private $error = null;
	
	/**
	 * Der Konstruktor stattet die DAO mit einem DB Objekt aus
	 */
	function __construct() {
		if (!isset(self::$debug)) {
			self::$debug = DebugQuery::getInstance();
		}
		$this->db = DBFactory::getInstance();
	}
	
	/**
	 * Der Destruktor entfernt die Referenz auf das DB Objekt
	 */
	function __destruct() {
		unset($this->db);
	}
	
	/**
	 * Diese Methode gibt ein array mit allen Accessright Entitäten zurück.
	 * 
	 * Jedes Zugriffsrecht wird hierbei durch ein Accessright Objekt representiert.
	 * 
	 * @return numerisches array mit Accessright Objekten, wenn erfolgreich, sonst null und Fehler in error
	 */
	public function get_all() {
		// Wenn vorher ein Fehler aufgetreten ist, schlucken
		$this->handle_previous_error();
		
		$ret = array();
		
		// debug
		if (DEBUG_ENABLED)
			self::$debug->append("Loading all entities of Accessright from Database...\n");
			
		// Query zum laden aller Accessright Objekte aus der DB
		$sql = 'SELECT
					URL,
					RightID
				FROM
					Accessrights';
		
		// Query vorbereiten
		if (!$stmt = $this->db->prepare($sql)) {
			// Error in der DB Instanz
			$this->error = ERR_DATABASE_RETURNS_ERROR. $this->db->error;
			
			// debug
			if (DEBUG_ENABLED)
				self::$debug->append("Error in database object: %s\n", $this->error);
			
			return null;
		}
		
		// Query ausführen
		if (!$stmt->execute()) {
			// Error im Statement
			$this->error = ERR_STATEMENT_RETURNS_ERROR. $stmt->error;
			
			// debug
			if (DEBUG_ENABLED)
				self::$debug->append("Error in statment: %s\n", $this->error);
			
			return null;
		}
		
		// Ergebnis binden und auslesen
		$stmt->bind_result($url, $rightid);
		while($stmt->fetch()) {
			$ret[] = new Accessright($url, $rightid);
		}
		
		// Statement schließen
		$stmt->close();
		
		// debug
		if (DEBUG_ENABLED)
			self::$debug->append("Successfully loaded %d Accessright objects from database\n", count($ret));
		
		return $ret;
	} 
	
	/**
	 * Diese Methode liest die Entität von Accessright aus der Datenbank.
	 * Mit dieser Methode kann überprüft werden, ob eine bestimmte URL ein bestimmtes Zugriffsrecht
	 * besitzt.
	 * 
	 * Achtung: Ein Administrator hat das Recht jede Seite zu betrachten.
	 * 
	 * @param Accessright $accessright das zu prüfende Zugriffsrecht
	 * @return Accessright wenn vorhanden, sonst null
	 */
	public function get($accessright) {
		// Wenn vorher ein Fehler aufgetreten ist, schlucken
		$this->handle_previous_error();
		
		$ret = null;
		
		// debug
		if (DEBUG_ENABLED)
			self::$debug->append("Checking Accessright...\n");
			
		// Wenn das Admin Recht angefragt wird, dann direkt zurückgeben
		if (1 === $accessright->get_rightid()) {
			// debug
			if (DEBUG_ENABLED)
				self::$debug->append("Admin has the right to view any url.\n");
				
			return $accessright;
		}
		
		// Query zum laden der Accessright Entität mit der entsprechenden ID
		$sql = 'SELECT
					URL,
					RightID
				FROM
					Accessrights
				WHERE
					URL = ? AND
					RightID = ?';
		
		// Query vorbereiten
		if (!$stmt = $this->db->prepare($sql)) {
			// Error in der DB Instanz
			$this->error = ERR_DATABASE_RETURNS_ERROR. $this->db->error;
			
			// debug
			if (DEBUG_ENABLED)
				self::$debug->append("Error in database object: %s\n", $this->error);
			
			return null;
		}
		
		// Platzhalter ersetzen
		$stmt->bind_param('si', $accessright->get_url(), $accessright->get_rightid());
		
		// Query ausführen
		if (!$stmt->execute()) {
			// Error im Statement
			$this->error = ERR_STATEMENT_RETURNS_ERROR. $stmt->error;
			
			// debug
			if (DEBUG_ENABLED)
				self::$debug->append("Error in statment: %s\n", $this->error);
			
			return null;
		}
		
		// Ergebnis an variablen binden
		$stmt->bind_result($url, $rightid);
		
		// Es dürfte höchstens eine Accessright Entität gefunden worden sein
		while($stmt->fetch()) {
			$ret = new Accessright($url, $rightid); 
		}
		
		// Statement schließen
		$stmt->close();
		
		// debug
		if (DEBUG_ENABLED)
			self::$debug->append($ret ? "Access granted.\n" : "Access denied.\n");
		
		return $ret;
	}
	
	/**
	 * Diese Methode speichert ein Accessright Entität in die Datenbank
	 * 
	 * @param Accessright $accessright die Entität
	 * @return ID, falls erfolgreich, sonst null und Fehler in error
	 */
	public function save($accessright) {
		// Wenn vorher ein Fehler aufgetreten ist, schlucken
		$this->handle_previous_error();
		
		$ret = null;
		
		// debug
		if (DEBUG_ENABLED)
			self::$debug->append("Saving the Accessright entity '%s => %d' to the database...", $accessright->get_url(), $accessright->get_rightid() );
		
		// Prüfen, ob es die Accessright Entität schon gibt
		if ($this->get($accessright)) {
			$this->error = ERR_ENTITY_ALREADY_EXSISTS;
			
			// debug
			if (DEBUG_ENABLED)
				self::$debug->append("The entity already exsists.\n");
				
			return null;
		}
			
		// Query zum Speichern einer Accessright Entität
		$sql = 'INSERT INTO
					Accessrights(URL, RightID)
				VALUES
					(?, ?)';
		
		// Statement vorbereiten
		if (!$stmt = $this->db->prepare($sql)) {
			// Error in der DB Instanz
			$this->error = ERR_DATABASE_RETURNS_ERROR. $this->db->error;
			
			// debug
			if (DEBUG_ENABLED)
				self::$debug->append("Error in database object: %s\n", $this->error);
			
			return null;
		}
		
		// Platzhalter ersetzen
		$stmt->bind_param('si', $accessright->get_url(), $accessright->get_rightid());
		
		// Query ausführen
		if (!$stmt->execute()) {
			// Error im Statement
			$this->error = ERR_STATEMENT_RETURNS_ERROR. $stmt->error;
			
			// debug
			if (DEBUG_ENABLED)
				self::$debug->append("Error in statment: %s\n", $this->error);
			
			return null;
		}
		
		// AccessrightID auslesen
		$ret = $stmt->insert_id;
		
		// Gab es einen Fehler?
		if (!$ret) {
			// Error im Statement
			$this->error = ERR_STATEMENT_RETURNS_ERROR. $stmt->error;
			
			// debug
			if (DEBUG_ENABLED)
				self::$debug->append("Error in statment: %s\n", $this->error);
			
			return null;
		}
		
		// Statement schließen
		$stmt->close();
		
		// debug
		if (DEBUG_ENABLED)
			self::$debug->append("Accessright was saved successfully.\n");
		
		return $ret;
	}
	
	/**
	 * Diese Methode löscht die Accessright Entität aus der Datenbank
	 * 
	 * @param Accessright $accessright
	 */
	public function delete($accessright) {
		// Wenn vorher ein Fehler aufgetreten ist, schlucken
		$this->handle_previous_error();
		
		$ret = null;
		
		// debug
		if (DEBUG_ENABLED)
			self::$debug->append("Deleting Accessright from database.\n");
			
		// Query zum löschen der Accessright Entität
		$sql = 'DELETE FROM
					Accessrights
				WHERE
					URL = ? AND
					RightID = ?';
		
		// Statement vorbereiten
		if (!$stmt = $this->db->prepare()) {
			// Error in der DB Instanz
			$this->error = ERR_DATABASE_RETURNS_ERROR. $this->db->error;
			
			// debug
			if (DEBUG_ENABLED)
				self::$debug->append("Error in database object: %s\n", $this->error);
			
			return null;
		}
		
		// Platzhalter ersetzen
		$stmt->bind_param('si', $accessright->get_url(), $accessright->get_rightid());
		
		// Query ausführen
		if (!$stmt->execute()) {
			// Error im Statement
			$this->error = ERR_STATEMENT_RETURNS_ERROR. $stmt->error;
			
			// debug
			if (DEBUG_ENABLED)
				self::$debug->append("Error in statment: %s\n", $this->error);
			
			return null;
		}
		
		// Statement schließen
		$stmt->close();
		
		// Probieren, ob es die Entität noch gibt
		if ($this->getById($id)) {
			// Löschen hat nicht geklappt
			$this->error = ERR_ENTITY_WAS_NOT_DELETED. $id;
			
			// debug
			if (DEBUG_ENABLED)
				self::$debug->append("Accessright entity was not deleted.");
				
			return null;
		}
		
		// debug
		if (DEBUG_ENABLED)
			self::$debug->append("Accessright entity successfully deleted.");
		
		return $ret;
	}
	
	/**
	 * Gibt den error aus und leert den internen error cache
	 */
	public function get_error() {
		$err = $this->error;
		$this->error = null;
		return $err;
	}
	
	/**
	 * Behandelt vorhergegangene nicht ausgelesene errors
	 */
	private function handle_previous_error() {
		// Falls vorher mal ein error aufgetreten ist, jedoch der
		// Fehler nicht ausgelesen wurde, wird dieser jetzt verworfen
		if ($pre_error = $this->get_error()) {
			// debug
			if (DEBUG_ENABLED)
				self::$debug->append("Previous error was not read: '%s'\n", $pre_error);
		}
	}
}

?>